package cn.ithers.blog.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.ithers.blog.dao.RefreshTokenDao;
import cn.ithers.blog.dao.SettingDao;
import cn.ithers.blog.dao.UserDao;
import cn.ithers.blog.dao.UserNoAllDao;
import cn.ithers.blog.dto.*;
import cn.ithers.blog.pojo.RefreshToken;
import cn.ithers.blog.pojo.Setting;
import cn.ithers.blog.pojo.User;
import cn.ithers.blog.pojo.UserNoAll;
import cn.ithers.blog.response.ResponseResult;
import cn.ithers.blog.response.ResponseState;
import cn.ithers.blog.service.IUserService;
import cn.ithers.blog.utils.*;
import com.google.gson.Gson;
import com.wf.captcha.ArithmeticCaptcha;
import com.wf.captcha.GifCaptcha;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.mail.MessagingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import java.util.Date;
import java.util.Map;

/**
 * @Author: zhanghuan
 * @date: 2020/8/28 18:26
 * @description:
 */

@Slf4j
@Service
@Transactional
public class UserServiceImpl extends BaseService implements IUserService {

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private UserDao userDao;

    @Autowired
    private SettingDao settingDao;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private TaskService taskService;

    @Autowired
    private RefreshTokenDao refreshTokenDao;

    @Autowired
    private Gson gson;

    @Autowired
    private UserNoAllDao userNoAllDao;


    /**
     * 获取request
     *
     * @return
     */
    public HttpServletRequest getRequest() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert requestAttributes != null;
        return requestAttributes.getRequest();
    }

    //获取response
    public HttpServletResponse getResponse() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert requestAttributes != null;
        return requestAttributes.getResponse();
    }


    //图灵验证码的字体
    public static final int[] captcha_font_types = {Captcha.FONT_1
            , Captcha.FONT_2
            , Captcha.FONT_3
            , Captcha.FONT_4
            , Captcha.FONT_5
            , Captcha.FONT_6
            , Captcha.FONT_7
            , Captcha.FONT_8
            , Captcha.FONT_9
            , Captcha.FONT_10};

    /**
     * 初始化管理员账号
     *
     * @param initUserDTO
     * @param request
     * @return
     */
    @Override
    public ResponseResult initManagerAccount(InitUserDTO initUserDTO, HttpServletRequest request) {
        //检查是否有初始化
        Setting managerAccountState = settingDao.findOneByKey(Constants.Settings.MANAGER_ACCOUNT_INIT_STATE);
        if (managerAccountState != null) {
            return ResponseResult.FAILED("管理员账号已经初始化");
        }
        //没有初始化管理员，执行以下代码
        //检查数据
        if (StrUtil.isEmpty(initUserDTO.getUserName())) {
            return ResponseResult.FAILED("用户名不能为空");
        }
        if (StrUtil.isEmpty(initUserDTO.getPassword())) {
            return ResponseResult.FAILED("密码不能为空");
        }
        if (StrUtil.isEmpty(initUserDTO.getEmail())) {
            return ResponseResult.FAILED("邮箱不能为空");
        }
        User user = new User();
        user.setUserName(initUserDTO.getUserName());
        user.setUserName(initUserDTO.getPassword());
        user.setUserName(initUserDTO.getEmail());
        //补充数据 ,生成id
        user.setId(String.valueOf(idWorker.nextId()));
        //设置角色
        user.setRoles(Constants.User.ROLE_ADMIN);
        user.setAvatar(Constants.User.DEFAULT_AVATAR);
        user.setState(Constants.User.DEFAULT_STATE);
        //获取ip
        String remoteAddr = request.getRemoteAddr();
        log.info(remoteAddr);
        user.setLoginIp(remoteAddr);
        user.setRegIp(remoteAddr);
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        //对密码进行加密
        String encode = bCryptPasswordEncoder.encode(user.getPassword());
        user.setPassword(encode);
        //保存到数据库中
        userDao.save(user);
        //更新已经添加的标记
        //肯定没有初始化
        Setting setting = new Setting();
        setting.setId(idWorker.nextId() + "");
        setting.setKey(Constants.Settings.MANAGER_ACCOUNT_INIT_STATE);
        setting.setCreateTime(new Date());
        setting.setUpdateTime(new Date());
        setting.setValue("1");
        settingDao.save(setting);
        return ResponseResult.SUCCESS("初始化成功");
    }

    /**
     * 创建图灵验证码
     *
     * @param response
     * @param captchaKey
     */
    @Override
    public void createCaptcha(HttpServletResponse response, String captchaKey) throws Exception {
        //批判captchaKey不能为空或长度小于13
        if (StrUtil.isEmpty(captchaKey) || captchaKey.length() < 13) {
            return;
        }
        long key;
        try {
            //将字符串转换为数字
            key = Long.parseLong(captchaKey);
        } catch (Exception e) {
            return;
        }
        //可以用了
        // 设置请求头为输出图片类型
        response.setContentType("image/gif");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        //产生一个小于3的随机数只能为0，1，2
        int captchaType = RandomUtil.randomInt(3);
        Captcha targetCapcha = null;
        if (captchaType == 0) {
            // 三个参数分别为宽、高、位数
            targetCapcha = new SpecCaptcha(200, 60, 5);
        } else if (captchaType == 1) {
            // gif类型
            targetCapcha = new GifCaptcha(200, 60);
        } else {
            // 算术类型
            targetCapcha = new ArithmeticCaptcha(200, 60);
            targetCapcha.setLen(2);  // 几位数运算，默认是两位
        }
        // 设置字体,随机选择10中字体中的一个
        int index = RandomUtil.randomInt(captcha_font_types.length);
        // 设置类型，纯数字、纯字母、字母数字混合
        targetCapcha.setFont(captcha_font_types[index]);
        targetCapcha.setCharType(Captcha.TYPE_NUM_AND_UPPER);
        String content = targetCapcha.text().toLowerCase();
        log.info("captcha content == > " + content);
        //保存到redis,5分钟有效
        redisUtils.set(Constants.User.KEY_CAPTCHA_CONTENT + key, content, 60 * 5);
        // 输出图片流
        targetCapcha.out(response.getOutputStream());
    }

    /**
     * 发送邮件验证码
     * 使用场景：注册，找回密码、修改邮箱（输入新邮箱）
     * 注册(register)；如果已经注册过了，提示改邮箱已经注册过了
     * 找回密码(forget)：如果没有注册过，提示改邮箱没有注册
     * 修改邮箱(update)：如果已经注册了，提示改邮箱已经注册过了
     *
     * @param request
     * @param emailAddress
     * @return
     */
    @Override
    public ResponseResult sendEmail(String type, HttpServletRequest request, String emailAddress) {
        if (emailAddress == null) {
            return ResponseResult.FAILED("邮箱地址不可以为空");
        }
        //根据类型查询邮箱是否存在
        if ("register".equals(type) || "update".equals(type)) {
            User userByEmail = userDao.findOneByEmail(emailAddress);
            if (userByEmail != null) {
                ResponseResult.FAILED("该邮箱已注册");
            }
        } else if ("forget".equals(type)) {
            User userByEmail = userDao.findOneByEmail(emailAddress);
            if (userByEmail == null) {
                ResponseResult.FAILED("该邮箱未注册");
            }
        }
        //1.防止暴力发送，同一个邮箱,间隔不能超过60s,1小时内同一个ip最多发10次（短信最多发3次）
        String remoteAddr = request.getRemoteAddr();
        log.info("sendEmail------> ip--------->" + remoteAddr);
        if (remoteAddr != null) {
            remoteAddr = remoteAddr.replace(":", "_");
        }
        log.info("sendEmail------> ip--------->" + remoteAddr);
        //拿出来，如果没有就过
        //同一个ip发送的次数
        Integer ipSendTime = (Integer) redisUtils.get(Constants.User.KEY_EMAIL_SEND_IP + remoteAddr);

        if (ipSendTime != null && ipSendTime > 10) {
            return ResponseResult.FAILED("请不要频繁发送验证码");
        }
        //
        Object hasSendEmail = redisUtils.get(Constants.User.KEY_EMAIL_SEND_ADDRESS + emailAddress);
        if (hasSendEmail != null) {
            return ResponseResult.FAILED("请不要频繁发送验证码");
        }
        //2.检查邮箱地址是否正确
        boolean isEmailFormatOk = ValidatetUtils.isEmailAddressOk(emailAddress);
        if (!isEmailFormatOk) {
            return ResponseResult.FAILED("邮箱格式不正确");
        }
        //3.发送验证码100000~999999
        int code = RandomUtil.randomInt(999999);
        if (code < 10000) {
            code += 1000;
        }
        log.info("sendEmail----->code--->" + code);
        try {
            taskService.sendEmailVarifyCode(String.valueOf(code), emailAddress);
        } catch (MessagingException e) {
            return ResponseResult.FAILED("验证码发送失败");
        }
        //4.做记录
        //发送记录，code
        if (ipSendTime == null) {
            ipSendTime = 0;
        }
        ipSendTime++;
        //1小时有效期
        redisUtils.set(Constants.User.KEY_EMAIL_SEND_IP + remoteAddr, ipSendTime, 60 * 60);
        //保存邮箱，1分钟邮箱
        redisUtils.set(Constants.User.KEY_EMAIL_SEND_ADDRESS + emailAddress, "true", 60);
        //保存code,10分钟有效
        redisUtils.set(Constants.User.KEY_EMAIL_CODE_CONTENT + emailAddress, String.valueOf(code), 60 * 10);
        return ResponseResult.SUCCESS("验证码发送成功");
    }

    /**
     * 注册
     *
     * @param registerUserDTO
     * @param emailCode
     * @param captchaCode
     * @param request
     * @return
     */
    @Override
    public ResponseResult register(RegisterUserDTO registerUserDTO, String emailCode, String captchaCode, String captchaKey, HttpServletRequest request) {
        log.info("-------------注册中----------------");
        //1.检查输入的用户名是否为空
        String userName = registerUserDTO.getUserName();
        if (StrUtil.isEmpty(userName)) {
            return ResponseResult.FAILED("用户名不能为空");
        }
        //检查当前用户名是否已经注册

        User userByUserName = userDao.findOneByUserName(userName);
        if (userByUserName != null) {
            return ResponseResult.FAILED("此用户已经注册");
        }
        //2.检查输入的邮箱是否为空
        String email = registerUserDTO.getEmail();
        if (StrUtil.isEmpty(email)) {
            ResponseResult.FAILED("邮箱地址不能为空");
        }
        // 2.检查邮箱格式是否正确
        if (!ValidatetUtils.isEmailAddressOk(email)) {
            return ResponseResult.FAILED("邮箱格式不正确");
        }
        //3.检查该邮箱是否存在
        User userByEmail = userDao.findOneByEmail(email);
        if (userByEmail != null) {
            return ResponseResult.FAILED("邮箱已经被注册了");
        }
        //4.此时前端已经发送过来邮箱，检查输入的邮箱验证码是否正确
        String emailVerifyCode = (String) redisUtils.get(Constants.User.KEY_EMAIL_CODE_CONTENT + email);
        log.info("redis中的emailCode--->" + emailVerifyCode);
        if (StrUtil.isEmpty(emailVerifyCode)) {
            return ResponseResult.FAILED("邮箱验证码已失效");
        }
        log.info("----------------------------------");
        log.info("emailVerifyCode--------->" + emailVerifyCode);
        log.info("emailCode--------->" + emailCode);
        if (!emailVerifyCode.equals(emailCode)) {
            return ResponseResult.FAILED("邮箱验证码不正确");
        } else {
            //正确，删除redis里的
            redisUtils.del(Constants.User.KEY_EMAIL_CODE_CONTENT + email);
        }
        //5.图灵验证码
        String capthcaVerifyCode = (String) redisUtils.get(Constants.User.KEY_CAPTCHA_CONTENT + captchaKey);
        if (StrUtil.isEmpty(capthcaVerifyCode)) {
            return ResponseResult.FAILED("人类验证码已失效");
        }
        if (!capthcaVerifyCode.equals(captchaCode)) {
            return ResponseResult.FAILED("人类验证码不正确");
        } else {
            redisUtils.del(Constants.User.KEY_CAPTCHA_CONTENT + captchaKey);
        }
        //达到注册条件
        //6.对密码进行加密
        String password = registerUserDTO.getPassword();
        if (StrUtil.isEmpty(password)) {
            return ResponseResult.FAILED("密码不可以为空");
        }
        User user = new User();
        user.setUserName(registerUserDTO.getUserName());
        user.setEmail(registerUserDTO.getEmail());
        user.setAvatar(registerUserDTO.getAvatar());
        user.setSign(registerUserDTO.getSign());
        user.setPassword(bCryptPasswordEncoder.encode(password));
        //7.补全数据
        //包括注册ip登录ip
        String ipAddress = request.getRemoteAddr();
        user.setRegIp(ipAddress);
        user.setLoginIp(ipAddress);
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        user.setAvatar(Constants.User.DEFAULT_AVATAR);
        //设置角色
        user.setRoles(Constants.User.ROLE_NORMAL);
        user.setState("1");
        user.setId(idWorker.nextId() + "");
        //8.保存到数据库
        userDao.save(user);
        //9.返回结果
        return ResponseResult.GET(ResponseState.JOIN_SUCCESS);
    }

    /**
     * 登录
     *
     * @param captcha
     * @param captchaKey
     * @param loginUserDTO
     * @return
     */
    @Override
    public ResponseResult doLogin(String captcha,
                                  String captchaKey,
                                  LoginUserDTO loginUserDTO,
                                  String from) {
        //from 可能没有值
        //如果没有值就给它一个默认值,默认为移动端
        if (StrUtil.isEmpty(from) || !Constants.FORM_MOBILE.equals(from) && !Constants.FROM_PC.equals(from)) {
            from = Constants.FORM_MOBILE;
        }
        HttpServletResponse response = getResponse();
        HttpServletRequest request = getRequest();
        //从redis中拿出图灵验证码
        String captchaValue = (String) redisUtils.get(Constants.User.KEY_CAPTCHA_CONTENT + captchaKey);
        if (StrUtil.isEmpty(captchaValue)) {
            return ResponseResult.FAILED("人类验证码已失效");
        }
        if (!captcha.equals(captchaValue)) {
            return ResponseResult.FAILED("人类验证码不正确");
        }
        //验证成功后删除redis里的验证码
        redisUtils.del(Constants.User.KEY_CAPTCHA_CONTENT + captchaKey);
        //用户填的可能是用户名，或邮箱
        String account = loginUserDTO.getAccount();
        if (StrUtil.isEmpty(account)) {
            return ResponseResult.FAILED("账号不能为空");
        }
        String password = loginUserDTO.getPassword();
        if (StrUtil.isEmpty(password)) {
            return ResponseResult.FAILED("密码不能为空");
        }
        //账号是用户名
        User userFromDb = userDao.findOneByUserName(account);
        //如果通过用户名查不存在
        if (userFromDb == null) {
            //就去通过邮箱查找
            userFromDb = userDao.findOneByEmail(account);
        }
        if (userFromDb == null) {
            return ResponseResult.FAILED("用户名或密码错误");
        }
        //用户存在
        boolean matches = bCryptPasswordEncoder.matches(password, userFromDb.getPassword());
        if (!matches) {
            return ResponseResult.FAILED("用户名或密码错误");
        }
        //密码正确
        //判断用户状态，如果非正常，返回结果
        if (!"1".equals(userFromDb.getState())) {
            //账号被禁用
            return ResponseResult.ACCOUNT_DENIED();
        }
        //修改更新登录时间和登录ip
        userFromDb.setLoginIp(request.getRemoteAddr());
        userFromDb.setUpdateTime(new Date());
        //生成token
        createToken(response, userFromDb, from);
        return ResponseResult.SUCCESS("登录成功");
    }

    /**
     * 创建token
     *
     * @param response
     * @param userFromDb
     * @return token_key
     */
    public String createToken(HttpServletResponse response, User userFromDb, String from) {

        String odlTokenKey = CookieUtils.getCookie(getRequest(), Constants.User.COOKIE_TOKEN_KEY);
        //新的登录token来了，需要把旧的删除，防止多个手机同时登录，或多个pc同时登录
        //确保单端登录，删除redis里的token
        RefreshToken oldRefreshToken = refreshTokenDao.findOneByUserId(userFromDb.getId());

        if (Constants.FORM_MOBILE.equals(from)) {
            if (oldRefreshToken != null) {
                redisUtils.del(Constants.User.KEY_TOKEN + oldRefreshToken.getMobileTokenKey());
            }
            //根据来源删除refreshToken中对应的token_key
            refreshTokenDao.deleteMobileTokenKey(odlTokenKey);
        } else if (Constants.FROM_PC.equals(from)) {
            if (oldRefreshToken != null) {
                redisUtils.del(Constants.User.KEY_TOKEN + oldRefreshToken.getTokenKey());
            }
            refreshTokenDao.deletePcTokenKey(odlTokenKey);
        }
        //生成token,claims已经包含from了
        //把user信息写道claims中
        Map<String, Object> claims = ClaimsUtils.user2Claims(userFromDb, from);
        //token默认2小时
        String token = JwtUtils.createToken(claims);
        //返回token的md5值，token保存至redis
        //前端访问的时候，携带token的md5key，从redis获取即可
        String tokenKey = from + DigestUtils.md5DigestAsHex(token.getBytes());
        //保存tokend到redis,有效时期2小时
        redisUtils.set(Constants.User.KEY_TOKEN + tokenKey, token, Constants.TimeValueInSecond.HOUR_2);
        //把tokenkey写到cookies中
        //这个要动态获取，可以从request获取
        CookieUtils.setUpCookie(response, Constants.User.COOKIE_TOKEN_KEY, tokenKey);
        //先判断数据库里有每有refreshToken,如果有就更新，如果没有就创建
        RefreshToken refreshTokenFormDb = refreshTokenDao.findOneByUserId(userFromDb.getId());
        if (refreshTokenFormDb == null) {
            refreshTokenFormDb = new RefreshToken();
            refreshTokenFormDb.setId(idWorker.nextId() + "");
            refreshTokenFormDb.setCreatTime(new Date());
            refreshTokenFormDb.setUserId(userFromDb.getId());
        }
        //不管是过期还是重新登录，都生成/更新refreshToken
        //生成refreshToken,一个月
        String refreshTokenValue = JwtUtils.createRefreshToken(userFromDb.getId(), Constants.TimeValueInMillions.MONTH);
        //refreshToken tokenKey, 用户id,更新时间，创建时间

        refreshTokenFormDb.setRefreshToken(refreshTokenValue);

        //要判断来源，如果是移动端设为默认值，如果是pc端，设置到pc端
        if (Constants.FROM_PC.equals(from)) {
            refreshTokenFormDb.setTokenKey(tokenKey);
        } else {
            refreshTokenFormDb.setMobileTokenKey(tokenKey);
        }

        refreshTokenFormDb.setUpdateTime(new Date());
        refreshTokenDao.save(refreshTokenFormDb);
        return tokenKey;
    }

    /**
     * 通过携带的token_key检查用户是否有登录，如果登录，就返回用户信息
     *
     * @return
     */
    @Override
    public User checkUser() {
        //拿到token_key
        String tokenKey = CookieUtils.getCookie(getRequest(), Constants.User.COOKIE_TOKEN_KEY);
        log.info("checkUser----->tokenKey" + tokenKey);
        if (StrUtil.isEmpty(tokenKey)) {
            return null;
        }
        //从tokenKey中解析出user
        User user = parseByTokenKey(tokenKey);
        //从token中解析出此请求是什么端的
        String from = tokenKey.startsWith(Constants.FROM_PC) ? Constants.FROM_PC : Constants.FORM_MOBILE;
        if (user == null) {
            //过期了，根据refreshToken
            //1.去mysql中查询refreshToken
            //如果是从pc端，就以pc的token_key来查
            //如果是mobile来的就以mobileL来查
            RefreshToken refreshToken;
            if (Constants.FROM_PC.equals(from)) {
                refreshToken = refreshTokenDao.findOneByTokenKey(tokenKey);
            } else {
                refreshToken = refreshTokenDao.findOneByMobileTokenKey(tokenKey);
            }
            //2.如果不存在，就是当前访问没有登录
            if (refreshToken == null) {
                log.info("refreshToken为空");
                return null;
            }
            //3.如果存在，就解析refreshToken
            try {
                JwtUtils.parseJWT(refreshToken.getRefreshToken());
                //5.如果有效创建新的token,和新的refreshToken
                String userId = refreshToken.getUserId();
                User userFromDb = userDao.findOneById(userId);

                String newTokenKey = createToken(getResponse(), userFromDb, from);
                log.info("创建新的token");
                return parseByTokenKey(newTokenKey);
            } catch (Exception e1) {
                log.info("refreshToken过期了");
                //4.如果refreshToken过期了，就是当前访问没有登录，提示用户登录
                return null;
            }
        }
        return user;
    }

    /**
     * 获取用户信息
     *
     * @param userId
     * @return
     */
    @Override
    public ResponseResult getUserInfo(String userId) {
        //从数据库中获取
        User user = userDao.findOneById(userId);
        //判断结果
        if (user == null) {
            //如果不存在就返回不存在
            return ResponseResult.FAILED("用户不存在");
        }


        //如果存在就复制对象，清空密码，emial 登录ID，注册ip
        String userJson = gson.toJson(user);
        User newUser = gson.fromJson(userJson, User.class);
        newUser.setPassword("");
        newUser.setEmail("");
        newUser.setRegIp("");
        newUser.setLoginIp("");
        //返回结果
        return ResponseResult.SUCCESS("获取用户信息成功").setData(newUser);
    }

    /**
     * 检查用户该Emial是否已经注册了
     *
     * @param email 邮箱地址
     * @return SUCCESS-->已经注册了，FAILED-->没有注册
     */
    @Override
    public ResponseResult checkEmail(String email) {
        User user = userDao.findOneByEmail(email);

        return user == null ? ResponseResult.FAILED("该邮箱未注册") : ResponseResult.SUCCESS("该邮箱已注册");
    }

    @Override
    public ResponseResult checkUserName(String userName) {
        User user = userDao.findOneByUserName(userName);
        return user == null ? ResponseResult.FAILED("该用户名未注册") : ResponseResult.SUCCESS("该用户名已注册");
    }

    /**
     * 更新用户信息
     *
     * @param userId
     * @param updateInfoUserDTO
     * @return
     */
    @Override
    public ResponseResult updateUserInfo(String userId, UpdateInfoUserDTO updateInfoUserDTO) {
        //从token中中解析出user,为了校验权限
        //只有用户自己才可以修改自己的信息。
        User userFromTokenKey = checkUser();
        if (userFromTokenKey == null) {
            //账号未登录
            return ResponseResult.ACCOUNT_NOT_LOGIN();
        }
        //从token拿到userId,到数据可中查到对应的user

        User userFromDb = userDao.findOneById(userFromTokenKey.getId());


        //可以判断数据库中的id与接口中的id是否一致。
        if (!userFromDb.getId().equals(userId)) {
            //没有权限
            return ResponseResult.PERMISSION_DENIED();
        }
        //可以修改
        // 用户名,不可以为空
        if (!StrUtil.isEmpty(updateInfoUserDTO.getUserName())) {
            //检查修改后的用户名是否已经存在
            User userByUserName = userDao.findOneByUserName(updateInfoUserDTO.getUserName());
            if (userByUserName != null) {
                return ResponseResult.FAILED("该用户名已注册");
            }
            userFromDb.setUserName(updateInfoUserDTO.getUserName());

        }
        //可修改头像，头像不可为空
        if (!StrUtil.isEmpty(updateInfoUserDTO.getAvatar())) {
            userFromDb.setAvatar(updateInfoUserDTO.getAvatar());
        }
        // ，签名 可以为空
        userFromDb.setSign(updateInfoUserDTO.getSign());
        userFromDb.setUpdateTime(new Date());


        userDao.save(userFromDb);
        //干掉redis里的token，下一次请求，需要解析token,就会根据refreshtoken重新创建一个
        String cookieKey = CookieUtils.getCookie(getRequest(), Constants.User.COOKIE_TOKEN_KEY);

        redisUtils.del(cookieKey);
        return ResponseResult.SUCCESS("用户信息修改成功");
    }

    /**
     * 删除用户
     * 并不是正的删除而是修改状态
     * ps:需要管理的权限
     *
     * @param userId
     * @return
     */
    @Override
    public ResponseResult deleteUserById(String userId) {
        /* 可以删除了 */
        int result = userDao.deleteUserByUserId(userId);
        if (result > 0) {
            return ResponseResult.SUCCESS("删除成功");
        }
        return ResponseResult.FAILED("用户不存在");
    }

    /**
     * 获取用户列表
     * 需要管理员权限
     *
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public ResponseResult listUsers(int page, int pageSize) {

        //分页查询
        page = checkPage(page);
        //size也限制一下每一页不得少于10个
        pageSize = checkPageSize(pageSize);
        //根据注册日期来排序
        Sort sort = Sort.by(Sort.Direction.DESC, "createTime");

        Pageable pageable = PageRequest.of(page - 1, pageSize, sort);
        Page<UserNoAll> userList = userNoAllDao.findAll(pageable);

        return ResponseResult.SUCCESS("获取用户列表成功").setData(userList);

    }

    /**
     * 更新密码
     *
     * @param verifyCode
     * @param updatePasswordUserDTO
     * @return
     */
    @Override
    public ResponseResult updateUserPassword(String verifyCode, UpdatePasswordUserDTO updatePasswordUserDTO) {
        String email = updatePasswordUserDTO.getEmail();
        //检查邮箱是否有填写
        if (StrUtil.isEmpty(email)) {
            return ResponseResult.FAILED("邮箱不可以为空");
        }
        //根据邮箱区redis里拿验证码
        //进行对比
        String redisVerifyCode = (String) redisUtils.get(Constants.User.KEY_EMAIL_CODE_CONTENT + email);
        if (redisVerifyCode == null || !redisVerifyCode.equals(verifyCode)) {
            return ResponseResult.FAILED("请输入正确的验证码");
        }
        redisUtils.del(Constants.User.KEY_EMAIL_CODE_CONTENT + email);
        //修改密码
        int result = userDao.updatePasswordByEmaill(bCryptPasswordEncoder.encode(updatePasswordUserDTO.getPassword()), email);
        return result > 0 ? ResponseResult.SUCCESS("修改密码成功") : ResponseResult.FAILED("修改密码失败");
    }

    /**
     * 更新邮箱
     *
     * @param email
     * @param verifyCode
     * @return
     */
    @Override
    public ResponseResult updateEmail(String email, String verifyCode) {
        //1.确保已经登录了
        User user = this.checkUser();
        if (user == null) {
            //没有登录
            return ResponseResult.ACCOUNT_NOT_LOGIN();
        }
        //2.对比验证码,确保新邮箱属于当前用户
        String redisVerifyCode = (String) redisUtils.get(Constants.User.KEY_EMAIL_CODE_CONTENT + email);
        if (StrUtil.isEmpty(redisVerifyCode) || !redisVerifyCode.equals(verifyCode)) {
            return ResponseResult.FAILED("验证码错误");
        }
        //验证正确后，删除验证码
        redisUtils.del(Constants.User.KEY_EMAIL_CODE_CONTENT + email);
        //可以修改
        int result = userDao.updateEmialById(email, user.getId());
        return result > 0 ? ResponseResult.SUCCESS("邮箱修改成功咯") : ResponseResult.FAILED("邮箱修改失败啦");
    }

    @Override
    public ResponseResult doLogOut() {
        //拿到token_key
        String tokenKey = CookieUtils.getCookie(getRequest(), Constants.User.COOKIE_TOKEN_KEY);
        if (StrUtil.isEmpty(tokenKey)) {
            //账号未登录
            return ResponseResult.ACCOUNT_NOT_LOGIN();
        }
        //删除redis里的token,因为个端是独立的所有可以删除
        redisUtils.del(Constants.User.KEY_TOKEN + tokenKey);
        //删除数据库里的refreshToken
        //这个不做删除，只做更新
//        refreshTokenDao.deleteByTokenKey(tokenKey);
        if (Constants.FROM_PC.startsWith(tokenKey)) {
            refreshTokenDao.deletePcTokenKey(tokenKey);
        } else {
            refreshTokenDao.deleteMobileTokenKey(tokenKey);

        }
        //删除cookie
        CookieUtils.deleteCookie(getResponse(), Constants.User.COOKIE_TOKEN_KEY);


        return ResponseResult.SUCCESS("退出登录成功");
    }

    /**
     * 解析token 是从pc端 还是移动端来的,使用要判空
     *
     * @param tokenKey
     * @return
     */
    private String parseForm(String tokenKey) {

        String token = (String) redisUtils.get(Constants.User.KEY_TOKEN + tokenKey);
        if (token != null) {
            try {
                Claims claims = JwtUtils.parseJWT(token);
                return ClaimsUtils.getFrom(claims);
            } catch (Exception e) {
                log.info("parseByTokenKey----------->" + "过期了");
                return null;
            }
        }
        return null;
    }

    /**
     * 解析token得到user
     *
     * @param tokenKey
     * @return
     */
    private User parseByTokenKey(String tokenKey) {
        String token = (String) redisUtils.get(Constants.User.KEY_TOKEN + tokenKey);
        if (token != null) {
            try {
                Claims claims = JwtUtils.parseJWT(token);
                return ClaimsUtils.claims2User(claims);
            } catch (Exception e) {
                log.info("parseByTokenKey----------->" + "过期了");
                return null;
            }
        }
        return null;

    }

}
